// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: declaration of CXFormsXPathFunctions.
//   $Id$


// XFormsXPathFunctions.h : Declaration of the CXFormsXPathFunctions
#pragma once
#ifndef __XFORMSXPATHFUNCTIONS_H_
#define __XFORMSXPATHFUNCTIONS_H_

#include "resource.h"       // main symbols
#include "XFormsXFormsElement.h"	// Added by ClassView
#include <stack>
#include <Common/COM/msw/MultiIDispatch.h>

typedef CMultiIDispatch<CXFormsXPathFunctions> CXFormsXPathFunctionsMultiIDispatch;

typedef IDispatchImpl<IXFormsXPathFunctions, &IID_IXFormsXPathFunctions, &LIBID_XFORMSLib,1,17> XPathFunctionsDispatch1;
typedef IDispatchImpl<IXFormsXPathFunctions3, &IID_IXFormsXPathFunctions3, &LIBID_XFORMSLib,1,17> XPathFunctionsDispatch3;
typedef IDispatchImpl<IXFormsXPathFunctions4, &IID_IXFormsXPathFunctions4, &LIBID_XFORMSLib,1,17> XPathFunctionsDispatch4;
typedef IDispatchImpl<IXFormsXPathFunctions5, &IID_IXFormsXPathFunctions5, &LIBID_XFORMSLib,1,17> XPathFunctionsDispatch5;
typedef IDispatchImpl<IXFormsXPathFunctions6, &IID_IXFormsXPathFunctions6, &LIBID_XFORMSLib,1,17> XPathFunctionsDispatch6;

typedef std::stack< CComPtr<IXMLDOMNode> > CNodeStack;
/////////////////////////////////////////////////////////////////////////////
// CXFormsXPathFunctions
class ATL_NO_VTABLE CXFormsXPathFunctions : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CXFormsXPathFunctions, &CLSID_XFormsXPathFunctions>,
	public XPathFunctionsDispatch1
	,public XPathFunctionsDispatch3
	,public XPathFunctionsDispatch4
	,public XPathFunctionsDispatch5
	,public XPathFunctionsDispatch6
	,public CXFormsXPathFunctionsMultiIDispatch
{
		friend class CXFormsXFormsElement;
public:
	CXFormsXPathFunctions()
		:m_pOwnerForm(0)
		
	{
	}

DECLARE_REGISTRY_RESOURCEID(IDR_XFORMSXPATHFUNCTIONS)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CXFormsXPathFunctions)
	COM_INTERFACE_ENTRY(IXFormsXPathFunctions)
	COM_INTERFACE_ENTRY(IXFormsXPathFunctions3)
	COM_INTERFACE_ENTRY(IXFormsXPathFunctions4)
	COM_INTERFACE_ENTRY(IXFormsXPathFunctions5)
	COM_INTERFACE_ENTRY(IXFormsXPathFunctions6)
	COM_INTERFACE_ENTRY2(IDispatch,IXFormsXPathFunctions)
END_COM_MAP()

#pragma warning(disable:4244)
	BEGIN_MULTI_DISPATCH_MAP(CXFormsXPathFunctions)
		MULTI_DISPATCH_ENTRY(XPathFunctionsDispatch1)
		MULTI_DISPATCH_ENTRY(XPathFunctionsDispatch3)
		MULTI_DISPATCH_ENTRY(XPathFunctionsDispatch4)
		MULTI_DISPATCH_ENTRY(XPathFunctionsDispatch5)
		MULTI_DISPATCH_ENTRY(XPathFunctionsDispatch6)
	END_MULTI_DISPATCH_MAP()
#pragma warning(default:4244)

// IXFormsXPathFunctions
public:
	//Override GetIdsOfNames to fix non-idl-token
	//	XPath method names
	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid ); 
	STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo,UINT *puArgErr)
	{
		HRESULT hr;
		switch(dispidMember)
		{
			case 9:
			case 1:
			case 12:
			case 13:
			case 10:
			case 5:
			case 6:
			case 16:
			case 11:
				hr =XPathFunctionsDispatch1::Invoke(dispidMember,  riid,  lcid,  wFlags,  pdispparams,  pvarResult,  pexcepinfo, puArgErr);
				break;
			case 22:
			case 23:
			case 24:
			case 25:
			case 26:
				hr =XPathFunctionsDispatch6::Invoke(dispidMember,  riid,  lcid,  wFlags,  pdispparams,  pvarResult,  pexcepinfo, puArgErr);
				break;
			default:		
				hr = CXFormsXPathFunctionsMultiIDispatch::Invoke(dispidMember,  riid,  lcid,  wFlags,  pdispparams,  pvarResult,  pexcepinfo, puArgErr);
		}
		return hr;
	}
	STDMETHOD(months)(VARIANT vtDuration, /*[out,retval]*/ double * pdblMonths);
	STDMETHOD(seconds)(VARIANT vtDuration, /*[out,retval]*/ double * pdblseconds);
	STDMETHOD(secondsFromDateTime)(VARIANT vtDate,/*[out,retval]*/ double * pdblSeconds);
	STDMETHOD(daysFromDate)(VARIANT vtDate, /*[out,retval]*/ double * dblDays);
	STDMETHOD(instance)(VARIANT vtInstanceId,/*[out,retval]*/ IXMLDOMNodeList ** ppRetval);
	STDMETHOD(globalInstance)(VARIANT InstanceId,/*[out,retval]*/ IXMLDOMNodeList ** ppRetval);
	STDMETHOD(_if)(BOOL bCondition, VARIANT vtIfTrue, VARIANT vtIfFalse, /*[out,retval]*/ BSTR * sRet);
	STDMETHOD(booleanFromString)(VARIANT vtBool,VARIANT *vtReturnBool);
	STDMETHOD(property)(/*[in]*/VARIANT vtProp,/*[out,retval]*/BSTR* val);
	STDMETHOD(index)(VARIANT vtId, double* retval);
	//IXFormsXPathFunctions3
	STDMETHOD(evaluate)(VARIANT vtInput, VARIANT * pvtRetval);
	//IXFormsXPathFunctions4
	STDMETHOD(valid)(IXMLDOMNodeList * pNl, BOOL * pbRetval);
	//The following functions have no private version, 
	//	They must be called with the given arguments
	STDMETHOD(countNonEmpty)(IDispatch *pNodeSet, long *retval);
	STDMETHOD(_max)(/*[in]*/IDispatch * pNodeSet,/*[out,retval]*/ double* dblRetVal);
	STDMETHOD(_min)(/*[in]*/IDispatch * pNodeSet,/*[out,retval]*/ double* dblRetVal);
	STDMETHOD(avg)(/*[in]*/IDispatch * pNodeSet,/*[out,retval]*/ double* dblRetVal);
	STDMETHOD(now)(/*[out,retval]*/BSTR * psRetval);
	STDMETHOD(StripDisabledNodes)(IXMLDOMNodeList * pNl,/*[out,retval]*/IXMLDOMNodeList ** ppRetval);

	//XForms 1.1 functions.
	 STDMETHOD(power)(VARIANT argBase,VARIANT argExponent, double * pdRetval);		
	 STDMETHOD(luhn)(VARIANT argLuhn, BOOL * pbRetval);		
	 STDMETHOD(_id)(VARIANT argIDList, IXMLDOMNodeList ** ppRetval);		
	 STDMETHOD(daysToDate)(VARIANT argDays, BSTR * pbsRetval);		
	 STDMETHOD(secondsToDateTime)(VARIANT argSeconds, BSTR * pbsRetval);		
	 STDMETHOD(localDate)( BSTR * pbsRetval);		
	 STDMETHOD(localDateTime)( BSTR * pbsRetval);		
	 STDMETHOD(encode)(VARIANT argData,VARIANT argEncoding, BSTR * pbsRetval);		
	 STDMETHOD(decode)(VARIANT argData,VARIANT argEncoding, BSTR * pbsRetval);		
	 STDMETHOD(digest)(VARIANT argData, VARIANT argHashingAlgorithm,VARIANT argEncoding, BSTR * pbsRetval);		
	 STDMETHOD(hmac)( VARIANT argKey, VARIANT argData, VARIANT argHashingAlgorithm, VARIANT argEncoding, BSTR * pbsRetval);		
	 STDMETHOD(random)( VARIANT argDoSeeding, double * pdRetval);		


private:
	HRESULT TransformNodeToRemoveIrrelevantNodes(IXMLDOMNode * pNode , VARIANT * pvtData);
	//String based (internal) versions of COM exposed functions
	STDMETHOD(booleanFromString)(BSTR sBool,/*[out,retval]*/VARIANT *vtReturn);
	STDMETHOD(property)(/*[in]*/BSTR prop,/*[out,retval]*/BSTR* val);
	STDMETHOD(index)(BSTR sId, double * retval);
	STDMETHOD(months)(BSTR sDuration, /*[out,retval]*/ double * pdblMonths);
	STDMETHOD(seconds)(BSTR sDuration, /*[out,retval]*/ double * pdblseconds);
	STDMETHOD(secondsFromDateTime)(BSTR sDate,/*[out,retval]*/ double * pdblSeconds);
	STDMETHOD(daysFromDate)(BSTR sDate, /*[out,retval]*/ double * dblDays);
	STDMETHOD(instance)(BSTR InstanceId,/*[out,retval]*/ IXMLDOMNodeList ** ppRetval);
	STDMETHOD(globalInstance)(BSTR InstanceId,/*[out,retval]*/ IXMLDOMNodeList ** ppRetval);
	//not needed.
	//STDMETHOD(_if)(BOOL bCondition, BSTR bIfTrue, BSTR bIfFalse, /*[out,retval]*/ BSTR * sRet);
	//<summary>
	//	Used by instance and globalInstance to return a nodeset containing
	//	the document element of the given instance.
	//</summary>
	//<returns>
	//	S_OK if a nodeset of more than 0 elements is returned;<br />
	//	S_FALSE if either pInstance is NULL, or its document is empty; <br/>
	//	E_FAIL if pInstance has no document, or no document could be created to fetch an empty nodeset from.
	//</returns> 
	HRESULT GetDocumentElementNodeset(CImplInstance * pInstance,IXMLDOMNodeList ** ppRetval);
	CXFormsXFormsElement * m_pOwnerForm;
	std::stack<CImplModel *> m_ActiveModelStack;
	CNodeStack m_XPathContextStack;
	//<summary>sets the current XPath evaluation context</summary>
	void PushCurrentXPathContext(CNode * pContextInfo,CImplModel * pModel);
	void PopCurrentXPathContext();

	inline HRESULT 
		nodelistToNumber(
			IDispatch * pNl,
			double (__stdcall * pCompFunc)(double,double),
			double* dblRetVal);

template <class T> inline static T __stdcall addTogether(T lhs,T rhs)
{
	return lhs + rhs;
}

template <class T> inline static T __stdcall mean(T lhs,T rhs)
{
	return (lhs + rhs)/2;
}

template <class T> inline static T __stdcall getHigherOf(T lhs,T rhs)
{
	return lhs > rhs ? lhs:rhs;
}

template <class T> inline static T __stdcall getLowerOf(T lhs,T rhs)
{
	return lhs < rhs ? lhs:rhs;
}

// Fetches a string from a variant argument as passed by XPath, extracts the string value of the first node if nodeset
HRESULT getStringFromVariant(const VARIANT & vtArg, BSTR * sRetval) const;
HRESULT getNumberFromVariant(const VARIANT & vtArg, double * sRetval) const;
HRESULT getBooleanFromVariant(const VARIANT & vtArg, bool * sRetval) const;
};

OBJECT_ENTRY_AUTO(__uuidof(XFormsXPathFunctions), CXFormsXPathFunctions)
#endif //__XFORMSXPATHFUNCTIONS_H_
